package com.mofe.zxy.filter;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import io.jsonwebtoken.*;
import io.jsonwebtoken.impl.TextCodec;
import io.jsonwebtoken.impl.crypto.MacSigner;
import io.jsonwebtoken.security.Keys;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;


/**
 * @ClassName: AuthenticationFilter
 * @Description: AuthenticationFilter
 * @Create by: ZhangXuYuan
 * @Date: 2022/4/14 8:41
 */

@Component
public class AuthenticationFilter implements GlobalFilter , Ordered {


    private static final String AUTHORIZE_TOKEN = "Authorization";

    private static final String SECURITY_TOKEN_PREFIX = "Bearer ";

    private static final String ADMIN_ID = "adminId";

    private static  final  String SIGN_KEY = "123456789123456789123456789123456789123456789123456789";




    private String noSecretKeyUrls = "/oauth/token,/oauth/check_token,/oauth/refresh_token";

    private String whiteIP = "";


    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();

        String uri = request.getURI().getPath();

        String token = request.getHeaders().getFirst(AUTHORIZE_TOKEN);

        if(hasSecurity(uri)) {
            return chain.filter(exchange);
        }



        Integer adminId = null;

        try {
            String tokenWithoutBearer = token.substring(7);
            System.out.println(tokenWithoutBearer);
            System.out.println(token);
            Claims claims= Jwts.parserBuilder()
                    //设置解密算法

                    .setSigningKey(SIGN_KEY.getBytes(StandardCharsets.UTF_8))
                    .build()
                    //解析token
                    .parseClaimsJws(tokenWithoutBearer)
                    .getBody();
             adminId = claims.get("adminId", Integer.class);
        } catch (ExpiredJwtException e) {
           return buildResponse(response,HttpStatus.UNAUTHORIZED,401,"token过期");
        } catch (SignatureException e) {
            return buildResponse(response,HttpStatus.UNAUTHORIZED,401,"签名异常");
        } catch (JwtException e) {
            e.printStackTrace();
            return buildResponse(response,HttpStatus.UNAUTHORIZED,401,"校验异常");
        } catch (Exception e) {
            return buildResponse(response,HttpStatus.UNAUTHORIZED,401,"非法token");
        }

        HttpHeaders headers = request.getHeaders();

        headers.add(ADMIN_ID,adminId.toString());

        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        return 0;
    }




    public static Mono<Void> buildResponse(ServerHttpResponse response, HttpStatus httpStatus, Integer code, String message) {
        response.setStatusCode(httpStatus);
        HttpHeaders httpHeaders = response.getHeaders();
        httpHeaders.add("Content-Type", "application/json; charset=UTF-8");
        httpHeaders.add("Cache-Control", "no-store, no-cache, must-revalidate, max-age=0");
        String returnMsg = JSONUtil.toJsonStr(new BaseResponse(403, "无token", message));
        DataBuffer bodyDataBuffer = response.bufferFactory().wrap(returnMsg.getBytes());
        return response.writeWith(Mono.just(bodyDataBuffer));
    }

    /**
     * 判断 当前的请求的地址中是否在已有的不拦截的地址中存在,如果存在 则返回true  表示  不拦截   false表示拦截
     *
     * @param uri 获取到的当前的请求的地址
     * @return
     */
    private boolean hasSecurity(String uri) {
        String[] split = noSecretKeyUrls.split(",");

        for (String patten : split) {
            if (patten.equals(uri)) {
                return true;
            }

            if (patten.endsWith("?") || patten.endsWith("*")) {
                if (checkUrl(patten, uri)) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 判断 当前的ip是否在ip白名单中,
     *
     * @param ip 获取到的当前的请求的地址
     * @return 包含返回true 不包含返回false
     */
    private boolean hasWhiteIP(String ip) {
        String[] split = whiteIP.split(",");

        for (String patten : split) {
            if (patten.equals(ip)) {
                return true;
            }

            if (patten.endsWith("?") || patten.endsWith("*")) {
                if (checkUrl(patten, ip)) {
                    return true;
                }
            }
        }
        return false;
    }

    private boolean checkUrl(String patten, String uri) {

        int indexOf = patten.lastIndexOf("/");
        String startStr = patten.substring(0, indexOf);

        if (!uri.startsWith(startStr)) {
            return false;
        }

        if (patten.endsWith("?")) {
            String[] pattenSplit = patten.split("/");
            String[] urlSplit = uri.split("/");

            if (!(pattenSplit.length == urlSplit.length)) {
                return false;
            }
        }

        return true;
    }
}
